import tkinter as tk
from tkinter import ttk
import serial
import serial.tools.list_ports
import threading

class SerialMonitor:
    def __init__(self, master):
        self.master = master
        master.title("MT76x8串口监视烧写工具")
        master.geometry("800x600")
        
        # 设置权重使组件可扩展
        master.grid_rowconfigure(1, weight=1)
        master.grid_columnconfigure(0, weight=1)
        
        # 串口设置区域
        self.setup_serial_frame()
        
        # 数据显示区域
        self.setup_display_frame()
        
        # 初始化串口对象
        self.serial_port = None
        self.is_running = False
        
    def setup_serial_frame(self):
        frame = ttk.LabelFrame(self.master, text="串口设置")
        frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")
        
        # 统一控件间距和对齐方式
        padx_val = 5
        pady_val = 5
        
        # 串口号选择
        ttk.Label(frame, text="串口号:").grid(row=0, column=0, padx=padx_val, pady=pady_val, sticky="w")
        self.port_combobox = ttk.Combobox(frame, width=20)
        self.port_combobox.grid(row=0, column=1, padx=padx_val, pady=pady_val, sticky="ew")
        self.refresh_ports()
        
        # 波特率选择
        ttk.Label(frame, text="波特率:").grid(row=1, column=0, padx=padx_val, pady=pady_val, sticky="w")
        self.baudrate_combobox = ttk.Combobox(frame, values=[
            "57600", "115200"
        ], width=20)
        self.baudrate_combobox.grid(row=1, column=1, padx=padx_val, pady=pady_val, sticky="ew")
        self.baudrate_combobox.current(0)  # 默认选中57600
        
        # 烧写类型
        ttk.Label(frame, text="烧写类型:").grid(row=2, column=0, padx=padx_val, pady=pady_val, sticky="w")
        self.program_combobox = ttk.Combobox(frame, values=["uboot", "固件"], state="readonly")
        self.program_combobox.grid(row=2, column=1, padx=padx_val, pady=pady_val, sticky="ew")
        self.program_combobox.current(0)
        
        # 文件名输入
        ttk.Label(frame, text="文件名:").grid(row=3, column=0, padx=padx_val, pady=pady_val, sticky="w")
        self.uboot_filename = tk.StringVar(value="bilink_7628_uboot.bin")
        self.uboot_entry = ttk.Entry(frame, textvariable=self.uboot_filename)
        self.uboot_entry.grid(row=3, column=1, padx=padx_val, pady=pady_val, sticky="ew")
        
        # 设置frame列权重，使右侧列可扩展
        frame.columnconfigure(3, weight=1)
        
        # 连接/断开按钮
        self.connect_button = ttk.Button(frame, text="连接", command=self.toggle_connection)
        self.connect_button.grid(row=3, column=3, padx=10, pady=5, sticky="se")
    
    def setup_display_frame(self):
        # 主容器
        container = ttk.LabelFrame(self.master, text="数据接收")
        container.grid(row=1, column=0, padx=10, pady=5, sticky="nsew")
        
        # 设置列权重使第3列对齐
        container.columnconfigure(3, weight=1)
        
        # 标题栏
        title_label = ttk.Label(container, text="接收窗口")
        title_label.grid(row=0, column=0, padx=5, pady=5, sticky="w")
        
        # 清除按钮放在第3列，与连接按钮右对齐
        clear_button = ttk.Button(container, text="清除", command=self.clear_display)
        clear_button.grid(row=0, column=3, padx=10, pady=5, sticky="e")
        
        # 设置权重使组件可扩展
        container.grid_rowconfigure(1, weight=1)
        container.grid_columnconfigure(0, weight=1)
        
        # 数据显示区域
        display_frame = ttk.Frame(container)
        display_frame.grid(row=1, column=0, columnspan=4, sticky="nsew")
        
        # 数据显示文本框
        self.text_display = tk.Text(display_frame)
        self.text_display.grid(row=0, column=0, sticky="nsew")
        
        # 滚动条
        scrollbar = ttk.Scrollbar(display_frame, command=self.text_display.yview)
        scrollbar.grid(row=0, column=1, sticky="ns")
        self.text_display.config(yscrollcommand=scrollbar.set)
        
        # 设置display_frame内部权重
        display_frame.grid_rowconfigure(0, weight=1)
        display_frame.grid_columnconfigure(0, weight=1)
    
    def clear_display(self):
        """清除接收窗口的数据"""
        self.text_display.delete(1.0, tk.END)
    
    def refresh_ports(self):
        ports = [port.device for port in serial.tools.list_ports.comports()]
        self.port_combobox["values"] = ports
        if ports:
            self.port_combobox.current(0)
    
    def toggle_connection(self):
        if self.serial_port and self.serial_port.is_open:
            self.disconnect_serial()
        else:
            self.connect_serial()
    
    def connect_serial(self):
        port = self.port_combobox.get()
        baudrate = int(self.baudrate_combobox.get())
        
        try:
            self.serial_port = serial.Serial(port, baudrate, timeout=1)
            self.is_running = True
            self.connect_button.config(text="断开")
            
            # 启动接收线程
            self.receive_thread = threading.Thread(target=self.receive_data)
            self.receive_thread.daemon = True
            self.receive_thread.start()
            
        except Exception as e:
            self.text_display.insert("end", f"连接失败: {str(e)}\n")
    
    def disconnect_serial(self):
        self.is_running = False
        if self.serial_port and self.serial_port.is_open:
            self.serial_port.close()
        self.connect_button.config(text="连接")
    
    def receive_data(self):
        buffer = ""
        while self.is_running and self.serial_port and self.serial_port.is_open:
            try:
                data = self.serial_port.read(self.serial_port.in_waiting or 1)
                if data:
                    text = data.decode("utf-8", errors="replace")
                    self.master.after(0, self.update_display, text)
                    
                    # 字符串匹配逻辑
                    buffer += text
                    if self.program_combobox.get() == "固件":
                        if "Please choose the operation:" in buffer:
                            self.serial_port.write(b"2")
                            buffer = ""
                        elif "Erase Linux in Flash then burn new one. Are you sure?(Y/N)" in buffer:
                            self.serial_port.write(b"y")
                            buffer = ""
                        elif "Input device IP (192.168.16.100) ==:192.168.16.100" in buffer:
                            self.serial_port.write(b"\r")
                            buffer = ""
                        elif "Input server IP (192.168.16.123) ==:192.168.16.123" in buffer:
                            self.serial_port.write(b"\r")
                            buffer = ""
                        elif "Input Linux Kernel filename () ==:" in buffer:
                            self.serial_port.write((self.uboot_filename.get() + "\r").encode())
                            buffer = ""
                    elif self.program_combobox.get() == "uboot":
                        if "Please choose the operation:" in buffer:
                            self.serial_port.write(b"9")
                            buffer = ""
                        elif "Erase Boot Loader in Flash then burn new one. Are you sure?(Y/N)" in buffer:
                            self.serial_port.write(b"y")
                            buffer = ""
                        elif "Input device IP (192.168.16.100) ==:192.168.16.100" in buffer:
                            self.serial_port.write(b"\r")
                            buffer = ""
                        elif "Input server IP (192.168.16.123) ==:192.168.16.123" in buffer:
                            self.serial_port.write(b"\r")
                            buffer = ""
                        elif "Input Uboot filename () ==:" in buffer:
                            self.serial_port.write((self.uboot_filename.get() + "\r").encode())
                            buffer = ""
                    
            except Exception as e:
                self.master.after(0, self.text_display.insert, "end", f"接收错误: {str(e)}\n")
                break
    
    def update_display(self, text):
        self.text_display.insert("end", text)
        self.text_display.see("end")
    
    def on_closing(self):
        self.disconnect_serial()
        self.master.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = SerialMonitor(root)
    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()
